﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ProgNetComponentsDx.Forms;
using DevExpress.XtraEditors;

namespace ProgNetComponentsDx.Controls
{
    /// <summary>
    /// Base background control
    /// </summary>
    public partial class BackgroundControlBase : XtraUserControl
    {

        private const string defLine = "linia 1\r\nlinia 2";
        #region fields
        /// <summary>
        /// Progress type
        /// </summary>
        protected ProgressType _ProgressType = ProgressType.Percentage;
        /// <summary>
        /// Is canceling
        /// </summary>
        protected bool _IsCanceling;

        /// <summary>
        /// Is running
        /// </summary>
        protected bool _IsRunning;
        #endregion

        #region Properties

        /// <summary>
        /// Gets if operation is being canceled
        /// </summary>
        [Browsable(false)]
        public bool IsCanceling
        {
            get { return _IsCanceling; }
        }

        /// <summary>
        /// Gets if operation is running
        /// </summary>
        [Browsable(false)]
        public bool IsRunning
        {
            get { return _IsRunning; }
        }

        /// <summary>
        /// Gets or sets if operation can be canceled
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public bool SupportCancelation
        {
            get { return backgroundWorker1.WorkerSupportsCancellation; }
            set
            {
                SetSupportCancelation(value);
            }
        }
        
        /// <summary>
        /// Gets or sets if control should be hidden when operation hinishes
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public bool HideOnComplete
        {
            get;
            set;
        }
        
        /// <summary>
        /// Gets or sets progress type
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public ProgressType ProgressType
        {
            get { return _ProgressType; }
            set
            {
                _ProgressType = value;
                SetProgressVisibility();
            }
        }
        
        /// <summary>
        /// Gets or sets maximum progress
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public int MaxProgress
        {
            get { return progressBar.Properties.Maximum; }
            set { SetMaxProgress(value); }
        }

        /// <summary>
        /// Gets or sets if progress label should be visible
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public bool LabelProgressVisible
        {
            get
            {
                return lblProgress.Visible;
            }
            set
            {
                SetLabelVisibility(value);
            }
        }
        
        /// <summary>
        /// Gets or sets if second progress label should be visible
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public bool LabelProgress2Visible
        {
            get
            {
                return lblProgress2.Visible;
            }
            set
            {
                SetLabel2Visibility(value);
            }
        }
        
        /// <summary>
        /// Gets or sets text displayed when user tries to start operation(s) and control is already running
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public string BuisyText
        {
            get;
            set;
        }
        
        /// <summary>
        /// Gets or sets label text
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public string LabelText
        {
            get { return lblProgress.Text; }
            set { SetLabelText(value); }
        }
        
        /// <summary>
        /// Gets or sets second label text
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public string Label2Text
        {
            get { return lblProgress2.Text; }
            set { SetLabel2Text(value); }
        }

        /// <summary>
        /// Gets or sets current progress value
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public int Progress
        {
            get { return progressBar.Position; }
            set { SetProgress(value); }
        }

        /// <summary>
        /// Gets or sets if control is visible
        /// </summary>
        [Category(ProgNetComponents.Constants.Categories.ProgNetSettings)]
        public new bool Visible
        {
            get { return base.Visible; }
            set { base.Visible = value; }
        }
        #endregion

        #region events
        /// <summary>
        /// Event fires when progress is changed
        /// </summary>
        public event ProgressChangedEventHandler ProgressChanged;
        /// <summary>
        /// Event fires when operation is completed
        /// </summary>
        public event RunWorkerCompletedEventHandler RunWorkerCompleted;
        /// <summary>
        /// Event fires when operation is being canceled
        /// </summary>
        public event EventHandler Canceling;
        #endregion

        #region protected methods
        /// <summary>
        /// Sets SupportCancelation
        /// </summary>
        /// <param name="value"></param>
        protected void SetSupportCancelation(bool value)
        {
            if (btnCancel.InvokeRequired)
            {
                btnCancel.Invoke(new Action<bool>(SetSupportCancelation), value);
                return;
            }
            btnCancel.Visible = backgroundWorker1.WorkerSupportsCancellation = value;
        }

        /// <summary>
        /// Sets progress controls visibility depending on ProgressType
        /// </summary>
        protected void SetProgressVisibility()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(SetProgressVisibility));
                return;
            }

            if (ProgressType == ProgressType.Merque)
            {
                progressBar.Visible = false;
                marqueProgressBar.Visible = true;
            }
            else
            {
                marqueProgressBar.Visible = false;
                progressBar.Visible = true;
            }
        }

        /// <summary>
        /// Sets label visibility
        /// </summary>
        /// <param name="visible"></param>
        protected void SetLabelVisibility(bool visible)
        {
            if (lblProgress.InvokeRequired)
            {
                lblProgress.Invoke(new Action<bool>(SetLabelVisibility), visible);
                return;
            }
            lblProgress.Visible = visible;
        }

        /// <summary>
        /// Sets second label visibility
        /// </summary>
        /// <param name="visible"></param>
        protected void SetLabel2Visibility(bool visible)
        {
            if (lblProgress2.InvokeRequired)
            {
                lblProgress2.Invoke(new Action<bool>(SetLabel2Visibility), visible);
                return;
            }
            lblProgress2.Visible = visible;
        }

        /// <summary>
        /// Sets labels text
        /// </summary>
        /// <param name="text"></param>
        protected void SetLabelText(string text)
        {
            if (lblProgress.InvokeRequired)
            {
                lblProgress.Invoke(new Action<string>(SetLabelText), text);
                return;
            }
            if (!this.IsDesignMode() && defLine != text)
            {
                if (!lblProgress.Visible)
                    lblProgress.Visible = true;
            }
            lblProgress.Text = text;
        }

        /// <summary>
        /// Sets second labels text
        /// </summary>
        /// <param name="text"></param>
        protected void SetLabel2Text(string text)
        {
            if (lblProgress2.InvokeRequired)
            {
                lblProgress2.Invoke(new Action<string>(SetLabel2Text), text);
                return;
            } 
            if (!this.IsDesignMode() && defLine != text)
            {
                if (!lblProgress2.Visible)
                    lblProgress2.Visible = true;
            }
            lblProgress2.Text = text;
        }

        /// <summary>
        /// Sets  progress
        /// </summary>
        /// <param name="progress"></param>
        protected void SetProgress(int progress)
        {
            if (progressBar.InvokeRequired)
            {
                progressBar.Invoke(new Action<int>(SetProgress), progress);
                return;
            }
            if (progress <= progressBar.Properties.Maximum &&
                progress >= progressBar.Properties.Minimum)
                progressBar.Position = progress;
        }

        /// <summary>
        /// Sets maximum progress
        /// </summary>
        /// <param name="progress"></param>
        protected void SetMaxProgress(int progress)
        {
            if (progressBar.InvokeRequired)
            {
                progressBar.Invoke(new Action<int>(SetMaxProgress), progress);
                return;
            }
            progressBar.Position = 0;
            progressBar.Properties.Maximum = progress;
        }
        #endregion

        #region CTOR
        /// <summary>
        /// Default constructor
        /// </summary>
        public BackgroundControlBase()
        {
            InitializeComponent();
            BuisyText = "Operacja w toku.";
        }
        #endregion

        #region private impl
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (ProgressChanged != null)
            {
                ProgressChanged(sender, e);
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (RunWorkerCompleted != null)
                RunWorkerCompleted(sender, e);

            this.marqueProgressBar.Properties.Stopped = true;
            this.progressBar.Position = 0;
            this.LabelText = this.Label2Text = "";
            this.btnCancel.Enabled = false;
            _IsRunning = false;
            if (HideOnComplete)
                Hide();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            OnDoWork();
        }
        
        private void btnCancel_Click(object sender, EventArgs e)
        {
            _IsCanceling = true;
            if (Canceling != null)
                Canceling(this, EventArgs.Empty);
            backgroundWorker1.CancelAsync();
        }
        #endregion

        /// <summary>
        /// On load
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!this.IsDesignMode())
            {
                if (lblProgress.Text == defLine)
                    lblProgress.Text = "";
                if (lblProgress2.Text == defLine)
                    lblProgress2.Text = "";
            }
        }

        /// <summary>
        /// Starts operation(s)
        /// </summary>
        public virtual void Start()
        {
            if (_IsRunning)
            {
                this.FindForm().ShowDxInfoDialog(BuisyText);
                return;
            }
            _IsRunning = true;
            _IsCanceling = false;
            this.btnCancel.Enabled = true;
            this.marqueProgressBar.Properties.Stopped = false;
            if (!this.Visible)
                Show();
            RunMainWorker();
        }

        /// <summary>
        /// Cancels operation
        /// </summary>
        public void Cancel()
        {
            if (this.SupportCancelation)
                btnCancel.PerformClick();
        }

        #region virtual to override
        /// <summary>
        /// Runs main background worker
        /// </summary>
        protected virtual void RunMainWorker()
        {
            throw new NotImplementedException("RunMainWorker");
        }

        /// <summary>
        /// Main workers Work function
        /// </summary>
        protected virtual void OnDoWork()
        {
            throw new NotImplementedException("OnDoWork");
        }
        #endregion

    }
}
